home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1999 March / EnigmA AMIGA RUN 35 (1999)(G.R. Edizioni)(IT)[!][issue 1999-03].iso / earcd / devel / vbcc-ppc-src / pasm / output_ehf.c < prev    next >
C/C++ Source or Header  |  1999-01-01  |  12KB  |  416 lines

  1. /* $VER: pasm output_ehf.c V1.2 (24.10.98)
  2.  *
  3.  * This file is part of pasm, a portable PowerPC assembler.
  4.  * Copyright (c) 1997-98  Frank Wille
  5.  *
  6.  * pasm is freeware and part of the portable and retargetable ANSI C
  7.  * compiler vbcc, copyright (c) 1995-98 by Volker Barthelmann.
  8.  * pasm may be freely redistributed as long as no modifications are
  9.  * made and nothing is charged for it. Non-commercial usage is allowed
  10.  * without any restrictions.
  11.  * EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
  12.  * SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
  13.  *
  14.  *
  15.  * v1.2   (24.10.98) phx
  16.  *        An empty section with reloc symbols will no longer be deleted.
  17.  *        Replaced obsolete R_PPC_TOC16 by real R_PPC_SDAREL16.
  18.  * v1.1d  (27.09.98) phx
  19.  *        fopen() uses binary mode "b" for windoze/msdog compatibility.
  20.  * v1.1b  (05.07.98) phx
  21.  *        Support for Chip/Fast-Ram sections (new .section-attributes
  22.  *        "C" and "F").
  23.  * v1.0   (02.05.98) phx
  24.  *        Empty EHF objects contain at least an empty CODE-hunk.
  25.  * v0.9   (24.03.98) phx
  26.  *        XDef for global symbols with type = @object was missing.
  27.  *        Use the name set by ".file" for the unit name and not the
  28.  *        one set by ".ident", which has no meaning for EHF.
  29.  * v0.7   (02.01.98) phx
  30.  *        Sections after a section with HUNK_EXT were 4 bytes too large.
  31.  *        Output format OFMT_ADOS support. The difference between ADOS and
  32.  *        and EHF is, that ADOS uses HUNK_CODE instead HUNK_PPC_CODE and
  33.  *        doesn't support any PPC-specific relocations and references types.
  34.  *        This makes it possible to link simple PowerPC programs with an
  35.  *        old linker, like BLink, SLink or PhxLnk.
  36.  * v0.4   (02.07.97) phx
  37.  *        File created.
  38.  */
  39.  
  40.  
  41. #define OUTPUT_EHF_C
  42. #include "ppcasm.h"
  43. #include "ehf.h"
  44.  
  45.  
  46. struct XRefNode {
  47.   struct node n;
  48.   char *sym_name;
  49.   uint8 ref_type;
  50.   int noffsets;
  51.   struct list xreflist;
  52. };
  53.  
  54.  
  55. static char *output_name;
  56. static int nsecs = 0;
  57. static bool exthunk;
  58.  
  59.  
  60. void output_ehf(struct GlobalVars *);
  61.  
  62. static void reloc_hunk(FILE *,struct Section *,uint8,uint32);
  63. static void unsupp_relocs(struct Section *);
  64. static void ext_header(FILE *);
  65. static void ext_refs(FILE *,struct GlobalVars *,struct Section *);
  66. static void ext_defs(FILE *,struct GlobalVars *,uint32,uint8,uint32);
  67. static uint32 word_strlen(char *);
  68. static void write_name(FILE *,struct GlobalVars *,char *);
  69. static void fwalign(FILE *,struct GlobalVars *,uint32);
  70. static void fw(FILE *,void *,size_t);
  71. static void fw4(FILE *,uint32);
  72.  
  73.  
  74.  
  75. void output_ehf(struct GlobalVars *gv)
  76. {
  77.   struct Section *nextsec,*sec=(struct Section *)gv->sectionlist.first;
  78.   struct Symbol *symchain;
  79.   uint32 index;
  80.   bool ehfmode = gv->output==OFMT_EHF;
  81.   bool empty = TRUE;
  82.   FILE *fp;
  83.  
  84.   /* assign an index to each valid section */
  85.   while (nextsec = (struct Section *)sec->n.next) {
  86.     if (!(sec->flags & SF_DISCARD) && sec->size > 0)
  87.       sec->index = nsecs++;
  88.     sec = nextsec;
  89.   }
  90.  
  91.   /* create output file */
  92.   output_name = gv->dest_name;
  93.  
  94.   if (fp = fopen(output_name,"wb")) {  /* create output file */
  95.     fw4(fp,HUNK_UNIT);
  96.     if (gv->file) {
  97.       fw4(fp,word_strlen(gv->file));  /* unit name */
  98.       write_name(fp,gv,gv->file);
  99.     }
  100.     else
  101.       fw4(fp,0);
  102.  
  103.  
  104.     /* section loop */
  105.     sec = (struct Section *)gv->sectionlist.first;
  106.     while (nextsec = (struct Section *)sec->n.next) {
  107.       exthunk = FALSE;
  108.       if (!(sec->flags & SF_DISCARD) &&
  109.           (sec->size > 0 || (sec->flags & SF_HASSYMS))) {
  110.         uint32 styp = HUNK_DATA;  /* default type */
  111.  
  112.         index = sec->index;
  113.         empty = FALSE;
  114.  
  115.         /* section name */
  116.         fw4(fp,HUNK_NAME);
  117.         fw4(fp,word_strlen(sec->name));
  118.         write_name(fp,gv,sec->name);
  119.  
  120.         /* section type and size */
  121.         switch(sec->type) {
  122.           case ST_CODE:
  123.             styp = ehfmode ? HUNK_PPC_CODE : HUNK_CODE;
  124.             break;
  125.           case ST_DATA:
  126.             styp = HUNK_DATA;
  127.             break;
  128.           case ST_UDATA:
  129.             styp = HUNK_BSS;
  130.             break;
  131.           default:  /* section type not supported in EHF/ADOS */
  132.             error(52,sec->name,(int)sec->type);
  133.             break;
  134.         }
  135.  
  136.         if (sec->flags & SF_CHIP)
  137.           styp |= HUNKF_CHIP;
  138.         else if (sec->flags & SF_FAST)
  139.           styp |= HUNKF_FAST;
  140.         fw4(fp,styp);
  141.         fw4(fp,(uint32)(sec->size+3)>>2);
  142.  
  143.         /* write section contents */
  144.         if (!(sec->flags & SF_UNINITIALIZED)) {
  145.           fw(fp,sec->contents,(uint32)sec->size);
  146.           fwalign(fp,gv,(uint32)sec->size);
  147.         }
  148.  
  149.         /* relocation hunks */
  150.         reloc_hunk(fp,sec,R_PPC_ADDR32,HUNK_ABSRELOC32);
  151. /* @@@  reloc_hunk(fp,sec,R_PPC_ADDR16,HUNK_ABSRELOC16); */
  152.         if (ehfmode)
  153.           reloc_hunk(fp,sec,R_PPC_REL24,HUNK_RELRELOC26);
  154.         reloc_hunk(fp,sec,R_PPC_REL14,HUNK_RELRELOC16);
  155.         reloc_hunk(fp,sec,R_PPC_REL14_BRTAKEN,HUNK_RELRELOC16);
  156.         reloc_hunk(fp,sec,R_PPC_REL14_BRNTAKEN,HUNK_RELRELOC16);
  157.         reloc_hunk(fp,sec,R_PPC_REL32,HUNK_RELRELOC32);
  158.         reloc_hunk(fp,sec,R_PPC_SDAREL16,HUNK_DREL16);
  159.         unsupp_relocs(sec);  /* print unsupported relocations */
  160.  
  161.         /* external references and global definitions */
  162.         ext_refs(fp,gv,sec);
  163.         ext_defs(fp,gv,index,SYM_RELOC,EXT_DEF);
  164.         if (index == 0)  /* put absolute definitions in first HUNK_EXT */
  165.           ext_defs(fp,gv,0xffff,SYM_ABS,EXT_ABS);
  166.         if (exthunk)
  167.           fw4(fp,0);  /* close HUNK_EXT block */
  168.  
  169.         /* symbol table */
  170.         ext_defs(fp,gv,index,SYM_RELOC,EXT_SYMB);
  171.  
  172.         fw4(fp,HUNK_END);  /* end of this hunk */
  173.       }
  174.       sec = nextsec;
  175.     }
  176.  
  177.     if (empty) {              /* there was not a single section */
  178.       fw4(fp,ehfmode ? HUNK_PPC_CODE : HUNK_CODE);
  179.       fw4(fp,0);
  180.       fw4(fp,HUNK_END);
  181.     }
  182.     fclose(fp);
  183.   }
  184.   else
  185.     error(25,output_name);  /* unable to create output file */
  186. }
  187.  
  188.  
  189. static void reloc_hunk(FILE *fp,struct Section *sec,uint8 r,uint32 ehfrel)
  190. /* generate an EHF relocation hunk for a specific reloc type */
  191. {
  192.   struct Reloc *nextrel,*rel=(struct Reloc *)sec->reloclist.first;
  193.   struct list **rlist=alloc(nsecs*sizeof(struct list *));
  194.   int *rcnt=alloczero(nsecs*sizeof(int));  /* reloc cnt for all sections */
  195.   bool hunk_required=FALSE;
  196.   int i;
  197.  
  198.   for (i=0; i<nsecs; i++) {  /* empty reloc lists for each section */
  199.     rlist[i] = alloc(sizeof(struct list));
  200.     initlist(rlist[i]);
  201.   }
  202.  
  203.   while (nextrel = (struct Reloc *)rel->n.next) {
  204.     if (rel->type == r) {
  205.       /* move reloc node of correct type into relocssect's rlist */
  206.       remnode(&rel->n);
  207.       addtail(rlist[rel->relocsect->index],&rel->n);
  208.       rcnt[rel->relocsect->index]++;
  209.       hunk_required = TRUE;
  210.     }
  211.     rel = nextrel;
  212.   }
  213.  
  214.   if (hunk_required) {  /* there's at least one relocation */
  215.     fw4(fp,ehfrel);  /* reloc hunk id */
  216.     for (i=0; i<nsecs; i++) {
  217.       if (rcnt[i]) {
  218.         fw4(fp,(uint32)rcnt[i]);  /* number of relocations */
  219.         fw4(fp,(uint32)i);  /* section index */
  220.  
  221.         /* store relocation offsets */
  222.         while(rel = (struct Reloc *)remhead(rlist[i])) {
  223.           fw4(fp,(uint32)rel->offset);
  224.           free(rel);
  225.         }
  226.       }
  227.     }
  228.     fw4(fp,0);  /* no more relocation entries */
  229.   }
  230.  
  231.   /* free dynamically allocated rlists and rcnt array */
  232.   for (i=0; i<nsecs; free(rlist[i++]));
  233.   free(rcnt);
  234. }
  235.  
  236.  
  237. static void unsupp_relocs(struct Section *sec)
  238. {
  239.   struct Reloc *nextrel,*rel=(struct Reloc *)sec->reloclist.first;
  240.  
  241.   while (nextrel = (struct Reloc *)rel->n.next) {
  242.     error(53,elfrel_name[rel->type & ELFRELNAMMSK],rel->offset,sec->name);
  243.     rel = nextrel;
  244.   }
  245. }
  246.  
  247.  
  248. static void ext_header(FILE *fp)
  249. {
  250.   if (!exthunk) {
  251.     exthunk = TRUE;
  252.     fw4(fp,HUNK_EXT);
  253.   }
  254. }
  255.  
  256.  
  257. static void ext_refs(FILE *fp,struct GlobalVars *gv,struct Section *sec)
  258. {
  259.   struct list xnodelist;  /* xrefs with same ref. type and symbol name */
  260.   struct XRefNode *xn,*nextxn;
  261.   struct XReference *xref;
  262.  
  263.   initlist(&xnodelist);
  264.   while (xref = (struct XReference *)remhead(&sec->xreflist)) {
  265.     char *name = xref->xsymbol->name;  /* name of xref'ed symbol */
  266.     uint8 rtype = xref->type;
  267.  
  268.     /* ELF32 -> EHF reference type mapping */
  269.     switch (rtype) {
  270.       case R_PPC_ADDR32:
  271.         rtype = EXT_ABSREF32;
  272.         break;
  273.       case R_PPC_REL14:
  274.       case R_PPC_REL14_BRTAKEN:
  275.       case R_PPC_REL14_BRNTAKEN:
  276.       case R_PPC_ADDR16:
  277.         rtype = EXT_RELREF16;
  278.         break;
  279.       case R_PPC_SDAREL16:
  280.         rtype = EXT_DEXT16;  /* small data */
  281.         break;
  282.       case R_PPC_REL24:
  283.         if (gv->output == OFMT_EHF) {
  284.           rtype = EXT_RELREF26;
  285.           break;
  286.         }
  287.       default:
  288.         error(53,elfrel_name[rtype & ELFRELNAMMSK],xref->offset,sec->name);
  289.         rtype = EXT_RELREF8;  /* @@@ to keep the loop running */
  290.         break;
  291.     }
  292.  
  293.     /* search appropriate XRefNode for referenced symbol and type */
  294.     xn = (struct XRefNode *)xnodelist.first;
  295.     while (nextxn = (struct XRefNode *)xn->n.next) {
  296.       if (!strcmp(name,xn->sym_name) && rtype==xn->ref_type)
  297.         break;
  298.       xn = nextxn;
  299.     }
  300.  
  301.     if (nextxn==NULL) {  /* we have to create a new XRefNode? */
  302.       xn = alloc(sizeof(struct XRefNode));
  303.       xn->sym_name = name;
  304.       xn->ref_type = rtype;
  305.       xn->noffsets = 0;
  306.       initlist(&xn->xreflist);
  307.       addtail(&xnodelist,&xn->n);
  308.     }
  309.  
  310.     /* add new offset to xreflist for same ref. type and symbol name */
  311.     addtail(&xn->xreflist,&xref->n);
  312.     xn->noffsets++;
  313.   }
  314.  
  315.   if (xnodelist.first->next) {  /* at least one reference in this section? */
  316.     ext_header(fp);
  317.     while (xn = (struct XRefNode *)remhead(&xnodelist)) {
  318.       fw4(fp,((uint32)xn->ref_type << 24) | word_strlen(xn->sym_name));
  319.       write_name(fp,gv,xn->sym_name);  /* symbol's name */
  320.       fw4(fp,(uint32)xn->noffsets);  /* number of references */
  321.       while (xref = (struct XReference *)remhead(&xn->xreflist)) {
  322.         fw4(fp,(uint32)xref->offset);  /* offset */
  323.         free(xref);
  324.       }
  325.       free(xn);
  326.     }
  327.   }
  328. }
  329.  
  330.  
  331. static void ext_defs(FILE *fp,struct GlobalVars *gv,uint32 idx,
  332.                      uint8 stype,uint32 xdeftype)
  333. {
  334.   struct Symbol *sym;
  335.   bool xdefs = FALSE;
  336.   int i;
  337.  
  338.   for (i=0; i<SYMHTABSIZE; i++) {
  339.     sym = gv->symbols[i];
  340.     while (sym) {
  341.       if (sym->type==stype && (sym->info==SYMI_NOTYPE || 
  342.           sym->info==SYMI_FUNC || sym->info==SYMI_OBJECT)) {
  343.         if (idx == ((stype==SYM_RELOC) ? sym->relsect->index : 0xffff)) {
  344.           if (sym->bind > SYMB_LOCAL) {
  345.             if (!xdefs) {
  346.               xdefs = TRUE;
  347.               if (xdeftype == EXT_SYMB)
  348.                 fw4(fp,HUNK_SYMBOL);
  349.               else
  350.                 ext_header(fp);
  351.             }
  352.  
  353.             /* generate xdef or symbol table entry */
  354.             fw4(fp,(xdeftype << 24) | word_strlen(sym->name));
  355.             write_name(fp,gv,sym->name);  /* symbol's name */
  356.             fw4(fp,sym->value);  /* ... and its value */
  357.           }
  358.         }
  359.       }
  360.       sym = sym->hash_chain;
  361.     }
  362.   }
  363.   if (xdefs && xdeftype==EXT_SYMB)
  364.     fw4(fp,0);  /* end of symbol table for this hunk */
  365. }
  366.  
  367.  
  368. static uint32 word_strlen(char *s)
  369. /* calculate number of 32 bit words required for
  370.    a string without terminator */
  371. {
  372.   uint32 l;
  373.  
  374.   if (l = (uint32)strlen(s))
  375.     l = (l+3)>>2;
  376.   return (l);
  377. }
  378.  
  379.  
  380. static void write_name(FILE *fp,struct GlobalVars *gv,char *name)
  381. /* write a unit/section/symbol name word-aligned */
  382. {
  383.   size_t nl=strlen(name);
  384.  
  385.   fw(fp,name,nl);
  386.   fwalign(fp,gv,(uint32)nl);
  387. }
  388.  
  389.  
  390. static void fwalign(FILE *fp,struct GlobalVars *gv,uint32 n)
  391. {
  392.   fw(fp,gv->alignment_bytes,(4-(n&3))&3);
  393. }
  394.  
  395.  
  396. static void fw(FILE *fp,void *buf,size_t len)
  397. {
  398.   if (len) {
  399.     if (!fwrite(buf,1,len,fp)) {
  400.       fclose(fp);
  401.       error(26,output_name);  /* write error */
  402.     }
  403.   }
  404. }
  405.  
  406.  
  407. static void fw4(FILE *fp,uint32 w)
  408. /* write a 32 bit word, automatic endian conversion */
  409. {
  410.   w = ECVW(w);
  411.   if (!fwrite(&w,1,sizeof(uint32),fp)) {
  412.     fclose(fp);
  413.     error(26,output_name);  /* write error */
  414.   }
  415. }
  416.